<?php
	class auth_code extends core {
		public $key             = 'auth_code';  // 键
		public $expire          = 3000;       // 验证码过期时间（s）
		public $img_back_flag   = true;  // 使用背景图片
		public $font_size       = 25;        // 验证码字体大小(px)
		public $curve_flag      = false;    // 是否画混淆曲线
		public $noise           = false;          // 是否添加杂点
		public $image_h         = 0;            // 验证码图片宽
		public $image_l         = 0;            // 验证码图片长
		public $length          = 4;             // 验证码位数
		public $backcolor       = array(243, 251, 254);  // 背景

		//private $code_set       = '346789ABCDEFGHJKLMNPQRTUVWXY';
		private $code_set       = '0123456789';
		private $image_obj      = null;  // 验证码图片实例
		private $color          = null;      // 验证码字体颜色

		/**
		 * 验证码输出
		 *
		 * @author zhouqi 2012-8-9 AM 10:26:49
		 */
		public function _entry() {
			// 图片宽(px)
			$this->image_l || $this->image_l = $this->length * $this->font_size * 1.5 + $this->font_size * 1.5;

			// 图片高(px)
			$this->image_h || $this->image_h = $this->font_size * 2;

			// 建立一幅 $this->image_l x $this->image_h 的图像
			$this->image_obj = imagecreate($this->image_l, $this->image_h);

			// 设置背景
			//imagecolorallocate($this->image_obj, $this->backcolor[0], $this->backcolor[1], $this->backcolor[2]);
			imagecolorallocate($this->image_obj, 255, 255, 255);

			// 验证码字体随机颜色
			$this->color = imagecolorallocate($this->image_obj, mt_rand(1,20), mt_rand(1,20), mt_rand(1,20));

			// 验证码使用随机字体
			$ttfPath = $this->_root() . '/static/font/';

			$dir = dir($ttfPath);
			$ttfs = array();
			while (false !== ($file = $dir->read()) && $dir) {
				if($file[0] != '.' && substr($file, -4) == '.ttf') {
					$ttfs[] = $ttfPath . $file;
				}
			}
			$dir->close();

			//$ttf = $ttfs[array_rand($ttfs)];
			$ttf = $ttfs[0];

			//背景图
			if($this->img_back_flag) {
				$this->_background();
			}

			//绘杂点
			if ($this->noise) {
				$this->_write_noise();
			}

			//干扰线
			if($this->curve_flag) {
				$this->_write_curve();
			}

			// 绘验证码
			$code = array(); // 验证码
			$code_nx = 0; // 验证码第N个字符的左边距
			for ($i = 0; $i < $this->length; $i++) {
				$code[$i] = $this->code_set[mt_rand(0, 9)];
				$code_nx += mt_rand($this->font_size * 1.2, $this->font_size * 1.6);

				// 写一个验证码字符
				imagettftext($this->image_obj, $this->font_size, mt_rand(-40, 40), $code_nx, $this->font_size * 1.5, $this->color, $ttf, $code[$i]);
			}

			//SESSION值
			$auth_val = array('code' => join('', $code), 'time' => time());

			set_session($this->key, $auth_val);

			header('Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate');
			header('Cache-Control: post-check=0, pre-check=0', false);
			header('Pragma: no-cache');
			header("content-type: image/png");
			ob_clean();
			// 输出图像
			imagepng($this->image_obj);
			imagedestroy($this->image_obj);
		}

		/**
		 * 验证码是否正确
		 *
		 * @author zhouqi 2012-8-9 AM 10:43:39
		 * @param string $code 值
		 */
		public function check($code) {
			$code_val = get_session($this->key);

			if($code_val['code'] != strtoupper($code)) {
				return false;
			}

			//过期
			if(time() - $code_val['time'] > $this->expire) {
				return false;
			}
			set_session($this->key, null);
			return true;
		}

		/*+-----------------------------私有--------------------------------+*/

		/**
		 * 绘制背景图片
		 *
		 * @author zhouqi 2012-8-9 AM 10:26:41
		 */
		private function _background() {
			$path = $this->_root() . '/static/app/auth_code/img/';
			$dir = dir($path);

			$bgs = array();
			while (false !== ($file = $dir->read())) {
				if($file[0] != '.' && substr($file, -4) == '.jpg') {
					$bgs[] = $path . $file;
				}
			}
			$dir->close();

			$gb = $bgs[array_rand($bgs)];

			list($width, $height) = @getimagesize($gb);
			// Resample
			$bgImage = @imagecreatefromjpeg($gb);
			@imagecopyresampled($this->image_obj, $bgImage, 0, 0, 0, 0, $this->image_l, $this->image_h, $width, $height);
			@imagedestroy($bgImage);
		}

		/**
		 * 画杂点
		 *
		 * @author zhouqi 2012-8-9 AM 10:29:24
		 */
		private function _write_noise() {
			for($i = 0; $i < 10; $i++){
				//杂点颜色
				$noiseColor = imagecolorallocate(
				$this->image_obj,
				mt_rand(150,225),
				mt_rand(150,225),
				mt_rand(150,225)
				);
				for($j = 0; $j < 5; $j++) {
					// 绘杂点
					imagestring(
					$this->image_obj,
					5,
					mt_rand(-10, $this->image_l),
					mt_rand(-10, $this->image_h),
					$this->code_set[mt_rand(0, 9)],// 杂点文本为随机的字母或数字
					$noiseColor
					);
				}
			}
		}

		/**
		 * 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数)
		 *
		 *      高中的数学公式咋都忘了涅，写出来
		 *        正弦型函数解析式：y=Asin(ωx+φ)+b
		 *      各常数值对函数图像的影响：
		 *        A：决定峰值（即纵向拉伸压缩的倍数）
		 *        b：表示波形在Y轴的位置关系或纵向移动距离（上加下减）
		 *        φ：决定波形与X轴位置关系或横向移动距离（左加右减）
		 *        ω：决定周期（最小正周期T=2π/∣ω∣）
		 *
		 */
		private function _write_curve() {
			$px = $py = 0;

			// 曲线前部分
			$A = mt_rand(1, $this->image_h / 2);                  // 振幅
			$b = mt_rand(-$this->image_h / 4, $this->image_h / 4);   // Y轴方向偏移量
			$f = mt_rand(-$this->image_h / 4, $this->image_h / 4);   // X轴方向偏移量
			$T = mt_rand($this->image_h, $this->image_l * 2);  // 周期
			$w = (2* M_PI)/$T;

			$px1 = 0;  // 曲线横坐标起始位置
			$px2 = mt_rand($this->image_l / 2, $this->image_l * 0.8);  // 曲线横坐标结束位置

			for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
				if ($w!=0) {
					$py = $A * sin($w*$px + $f)+ $b + $this->image_h / 2;  // y = Asin(ωx+φ) + b
					$i = (int) ($this->font_size / 5);
					while ($i > 0) {
						imagesetpixel($this->image_obj, $px , $py + $i, $this->color);  // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出（不用这while循环）性能要好很多
						$i--;
					}
				}
			}

			// 曲线后部分
			$A = mt_rand(1, $this->image_h / 2);                  // 振幅
			$f = mt_rand(-$this->image_h / 4, $this->image_h / 4);   // X轴方向偏移量
			$T = mt_rand($this->image_h, $this->image_l * 2);  // 周期
			$w = (2* M_PI)/$T;
			$b = $py - $A * sin($w*$px + $f) - $this->image_h / 2;
			$px1 = $px2;
			$px2 = $this->image_l;

			for ($px=$px1; $px<=$px2; $px=$px+ 0.9) {
				if ($w!=0) {
					$py = $A * sin($w*$px + $f)+ $b + $this->image_h / 2;  // y = Asin(ωx+φ) + b
					$i = (int) ($this->font_size / 5);
					while ($i > 0) {
						imagesetpixel($this->image_obj, $px, $py + $i, $this->color);
						$i--;
					}
				}
			}
		}
	}
?>